package cn.john.hrm.service.impl;
import cn.john.hrm.constant.CourseServiceContants;
import cn.john.hrm.domain.CourseType;
import cn.john.hrm.mapper.CourseTypeMapper;
import cn.john.hrm.service.ICourseTypeService;
import cn.john.hrm.util.AjaxResult;
import cn.john.hrm.vo.CrumbsVo;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * <p>
 * 课程目录 服务实现类
 * </p>
 *
 * @author john
 * @since 2021-06-20
 */

@Service
public class CourseTypeServiceImpl extends ServiceImpl<CourseTypeMapper, CourseType> implements ICourseTypeService {
    @Autowired
    private CourseTypeMapper courseTypeMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    private static ReentrantLock lock = new ReentrantLock();

    @Override
    public AjaxResult treeData() {
        // 在数据库中组装层级
        //List<CourseType> courseTypes = courseTypeMapper.treeData();
        // 在java代码中组装层级
        List<CourseType> courseTypes = new ArrayList<>();
        Object treeData = redisTemplate.opsForValue().get(CourseServiceContants.COURSE_TYPE_TREE_DATA);
        if (treeData != null) {
            // 如果redis不为空，则说明已经有数据，转型后直接返回
            courseTypes = (List<CourseType>) treeData;
            System.out.println("======>>>从Redis中查询");
        } else {
            if (lock.tryLock()) {
                try {
                    // 如果redis为空，则说明没有数据，从数据库中获取并且放入redis中一份再返回，可以解决缓存穿透
                    courseTypes = loadTreeData();
                    // 放入缓存中，并设置随机过期时间，以解决缓存雪崩问题
                    int expireTime = ThreadLocalRandom.current().nextInt(100, 200);
                    redisTemplate.opsForValue().set(CourseServiceContants.COURSE_TYPE_TREE_DATA, courseTypes,expireTime, TimeUnit.MINUTES);
                    System.out.println("======>>>从数据库中查询");
                } finally {
                    // 释放锁
                    lock.unlock();
                }
            } else {
                try {
                    // 如果不睡的话，会造成栈溢出的问题
                    Thread.sleep(100L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                treeData();
            }
        }
        return AjaxResult.me().setResultObj(courseTypes);
    }

    @Override
    public List<CrumbsVo> getCrumbs(Long id) {
        List<CrumbsVo> result = new ArrayList<>();
        // 根据id获取到当前类型的path 族谱
        CourseType courseType = courseTypeMapper.selectById(id);
        String path = courseType.getPath();
        // 以.号分割,.号是特殊符号，要用\\转义
        String[] ids = path.split("\\.");
        // 遍历
        for (String tid : ids) {
            CrumbsVo crumbsVo = new CrumbsVo();
            // 转型成Long类型
            Long pathId = Long.valueOf(tid);
            // 根据pathId先获取自己 再根据pid相等来获取bros
            CourseType own = courseTypeMapper.selectById(pathId);
            EntityWrapper<CourseType> wrapper = new EntityWrapper<>();
            // 找到和自己pid相等的bros
            wrapper.eq("pid", own.getPid());
            // 剔除自己
            wrapper.and().ne("id", own.getId());
            List<CourseType> bros = courseTypeMapper.selectList(wrapper);
            // 添加自己和兄弟
            crumbsVo.setOwn(own);
            crumbsVo.setBros(bros);
            // 添加到返回结果中
            result.add(crumbsVo);
        }
        return result;
    }

    @Override
    public boolean insert(CourseType entity) {
        // 延时双删
        // 第一次删除
        redisTemplate.delete(CourseServiceContants.COURSE_TYPE_TREE_DATA);
        // 更新数据库
        boolean result = super.insert(entity);
        // 延时
        try {
            Thread.sleep(10L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 第二次删除
        redisTemplate.delete(CourseServiceContants.COURSE_TYPE_TREE_DATA);
        return result;
    }

    @Override
    public boolean update(CourseType entity, Wrapper<CourseType> wrapper) {
        redisTemplate.delete(CourseServiceContants.COURSE_TYPE_TREE_DATA);
        return super.update(entity, wrapper);
    }

    @Override
    public boolean deleteById(Serializable id) {
        redisTemplate.delete(CourseServiceContants.COURSE_TYPE_TREE_DATA);
        return super.deleteById(id);
    }

    private List<CourseType> loadTreeData() {
        ArrayList<CourseType> result = new ArrayList<>();
        // 查询出所有数据
        List<CourseType> list = courseTypeMapper.selectList(null);
        // 装id和对象的关系
        HashMap<Long, CourseType> map = new HashMap<>();
        list.forEach(courseType -> {
            // id和对象的关系
            map.put(courseType.getId(), courseType);
        });
        // 组装数据
        list.stream().forEach(son -> {
            // 找出第一层级,pid=0的就是第一层级，第一层级没有父级
            if (son.getPid() == 0 ) {
                // 添加到结果中
                result.add(son);
            } else {
                // pid != 0 的其他层级
                // 如果自己的pid和其他层级的id相等，就找到了自己的父级对象，添加到父级对象的children中
                map.get(son.getPid()).getChildren().add(son);
            }
        });
        return result;
    }
}

